Shell学习笔记14-Shell脚本开发规范

GO


Shell脚本开发规范及习惯非常重要,有了好的规范和习惯,才能大大提升开发效率,降低后期的脚本维护成本,特别是在多人协作开发时,有一个互相遵守的规范显得特别重要。即使是自己一个人独自开发,也要采取一套科学的、固定的规范,这样脚本才更易读,易于后期维护。总之,就是要让自己养成一个一出手就是专业和规范的习惯。

1. Shell脚本基本规范

1.1. 一些基本规范

  • 在Shell脚本里,第一行通常用于指定脚本解释器。
    • 该行内容为:#!/bin/bash#!/bin/sh
    • 说明:此项在Linux系统场景下可能不是必须的,属于优秀规范和习惯
  • 在Shell脚本的开头处解释器代码后,最好加上版本版权等信息,如下:

    1
    2
    3
    4
    5
    #Date: 13:30 2018-03-01
    #Author: Theshu
    #Mail: theshu@qq.com
    #Function: This scripts function is...
    #Version: 0.1
    • 说明:可以在~/.vimrc配置文件时自动加上以上信息的功能。此项在Linux系统场景下不是必须的,属于优秀规范和习惯。
  • Shell脚本中尽量不要用中文注释,应用英文注释,以防止本机或切换系统环境后出现中文乱码的困扰。如果非要加中文,请根据自身的客户端对系统进行字符集调整,如:export LANG="zh_CN.UTF-8",并在脚本中重新定义字符集,使其和系统一致。
  • Shell脚本命名应以.sh为扩展名。例如:script-name.sh
  • Shell脚本应存放在固定的路径下,例如:/server/scripts

1.2. 代码书写技巧

  • 成对的符号应尽量一次写出来,然后退格在符号里增加内容,以防止遗漏。这些成对的符号包括:

    1
    {}、[]、''、``、""
  • 中括号[]两端至少要有一个空格,因此,键入中括号的时候即可留出空格[ ],然后再退格键入中间的内容,并确保两端都至少有一个空格。即:先键入一对中阔后,然后退一个格,输入两个空格,再退一个格,双中括号[[]]的写法也是如此。

  • 对于流程控制语句应一次将格式写完,再添加内容。

    • 比如:if语句的格式一次完成应为

      1
      2
      3
      4
      if 条件内容
      then
      内容
      fi
    • 再比如:for循环语句的格式一次完成应为

      1
      2
      3
      4
      for
      do
      内容
      done
    • 提示:while和until、case等语句也是一样。

  • 通过缩进让代码更易读,比如:

    1
    2
    3
    4
    5
    6
    7
    8
    if 条件内容
    then
    内容
    fi
    ############
    if 条件内容; then
    内容
    fi
  • 字符串赋值给变量时应加双引号,并且等号前后不能有空格。例如:THESHU_FILE="test.txt"

  • 脚本中的单引号、双引号及反引号,必须为英文状态下的符号,其实所有的Linux标准字符及符号都应该是英文状态下的符号,这一点需要特别注意。

2. Shell脚本变量命名及引用变量规范

2.1. 全局变量定义

全局变量也称环境变量,它的定义应全部大写,如APACHE_ERRAPACHEERR,名字对应的语义要尽量清晰,能够正确表达变量内容的含义,对于过长的英文单词可用前几个字符代替。多个单词间可用_符号连接,全局变量的定义一般放在系统的全局路径中,并且最好蚕蛹export来定义,全局变量一般可以在任意子Shell中直接使用(特殊情况除外,例如:定时任务执行Shell时就最好在Shell里重新定义这些全局变量,否则可能会出现问题)。

2.2. 局部变量定义

局部变量也成为普通变量,在常规脚本中,普通变量的命名也要尽可能统一,可以使用用驼峰语法,即第二个单词的首字母大写,如theshuHome,或者每个单词首字母大写,如TheshuHome,当然也有人喜欢采用全部大写或全部小写的方式,例如:theshuhomeTHESHUHOME。选择一种适合自己的方式即可。

Shell函数中的变量可以使用local方式进行定义,使之只在本函数作用域内有效,防止函数中的变量名称与外部程序中的变量相同,从而造成程序异常。下面是在函数中定义变量的例子:

1
2
3
4
5
6
7
function testFunc(){
local i
for ((i=0; i<5; i++))
do
echo "do something"
done
}

2.3. 变量的引用规范

在引用变量时,若变量前后都有字符,则需要使用${APACHE_ERR}(加大括号的方式)引用变量,以防止产生歧义;当变量内容为字符串时,需要使用"${APACHE_ERR}"(外面加双引号的方式)引用变量;当变量内容为整数时,则最好直接使用$APACHE_ERR来引用变量。全局变量、局部变量、函数变量、数组变量等都是如此。

  • 说明:对于需要环境变量的Java程序脚本等,在写脚本之前,最好通过export重新声明环境变量,一面在定时任务等场合的使用中出现问题。

3. Shell函数的命名及函数定义规范

Shell函数的命名可采用单词首字母大写的形式,如CreateFile(),并且语义要清晰,比如,使用CreateFile()代替CFILE()。也可以使用小写形式,如createfile()

可以加前后缀,如后缀为Max则为最大值,为Min则表示最小值,前缀Is为判断型函数,Get为取值函数,Do则为处理函数,这也有益于对函数功能的理解,使函数名更直观、更清晰。

范例:对操作系统函数库脚本的函数名进行定义:

1
2
3
4
5
6
7
8
9
# /etc/init.d/functions
if_ignored_file(){
case "$1" in
*~ | *.bak | *.orig | *.rpmnew | *.rpmorig | *.rpmsave
return 0
;;
esac
return 1
}

如果需要区别一些常规的字符串,可在函数名前加上function关键字,如下:

1
2
3
function CreateFile(){
...
}

显示函数返回值时,可在函数的结尾内容中包含return语句,并跟上返回值。即使是不关心返回值的函数,也可能在后续调用时无意识地去判断它的返回值并进行一系列动作,使用return语句不会带来多少负担,但确实能让函数的逻辑变得更加清晰和严谨。

范例:为操作系统函数库脚本函数定义return返回值

1
2
3
4
5
6
# Log a warning
warning(){
local rc=$?
[ "$BOOTUP" != "verbose" -a -z "${LSB:-}" ] && echo_warning
return $rc
}

4. Shell脚本(模块)高级命名规范

  • 常规的Shell脚本使用统一的后缀:.sh,例如theshu.sh
  • 模块的启动和停止脚本统一命名为start_模块名.shstop_模块名.sh
  • 监控脚本通常以*_mon.sh为后缀
  • 控制脚本一般以*_ctl.sh为后缀

5. Shell脚本的代码风格

5.1 代码框架

易变的信息(如报警的收件人、机器名、用户名密码、URL等)最好都定义为变量或使用特殊位置的参数,这会使开发的脚本更具通用性。

把Shell的通用变量以配置文件的形式单独存放,以功能.cfg来命令,例如nginx.conf,并放在conf目录下;引用时通过在脚本开头使用conf/nginx.conf的形式来加载。

将程序的功能分段、分模块采用函数等来实现,并存放到单独的函数文件里,如过是通用的公共函数可以存放在/etc/init.d/functions下,调用时采用source 文件全路径即可。

把脚本中的功能和配置明确分开,主脚本只用于实现程序主干,加载配置及加载函数等功能实现应尽量封装在子函数中。

规范代码树如下:

1
2
3
4
5
6
7
8
9
[root@theshu scripts]# tree
.
|-- bin
| `-- ipsecctl
|-- conf
| `-- ipsec.cfg
`-- func
`-- functions
3 directories, 3 files

5.2. 缩进规范

在使用条件语句时,每进行一层循环或是循环内部的操作时,就使用一个缩进,缩进一般用Tab键加空格。推荐采用4个空格缩进。

范例:写出脚本缩进规范:

1
2
3
4
5
6
7
8
9
if [ -d theshu_dir ]
then
cd theshu_dir
if [ -f theshu_file ]
then
echo "DoSth"
fi
cd ..
fi

提示:可调整Vim实现自动缩进,建议缩进4个空格。

6. Shell脚本的变量及文件检查规范

脚本中要检查配置项是否为空、是否可执行等,尤其是对于一些重要的、会影响下面脚本正常运行的配置想,必须要进行是否为空等的检查,避免配置文件中出现遗漏等问题。

范例:针对字符串变量进行判断:

1
2
3
4
if [ -n "${FILE_PATH}" ]
then
echo "Do something"
fi

范例:给出HTTP脚本变量的定义方式:

1
2
3
4
httpd=${HTTPD-/usr/sbin/httpd}
prog=httpd
pidfile=${PIDFILE-/var/run/httpd.pid}
lockfile=${LOCKFILE-/var/lock/subsys/httpd}

提示:这样的定义可以防止变量出现空着,这是变量子串的特殊知识。


OK

0%